package com.leaf.u_jvm;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * 
 * 线程等待演示
 *
 */
public class ThreadWaitDemo {

	/**
	 * 线程死锁循环
	 */
	public static void createBusyThread(){
		Thread thread = new Thread(new Runnable(){
			@Override
			public void run() {
				//观察会发现线程一直在执行空循环
				//线程处于RUNNABLE状态，没有归还执行令牌的动作，这种等待会消耗很多的CPU资源
				while(true){}
			}
		}, "testBusyThread");
		
		thread.start();
	}
	
	/**
	 * 线程等待演示
	 */
	public static void createLockThread(final Object lock){
		Thread thread = new Thread(new Runnable(){
			
			@Override
			public void run(){
				synchronized(lock){
					try {
						//等待lock对象的notify或notifyAll方法的出现，线程这时处于WAITING状态
						//在被唤醒前不会被分配执行时间
						//属于正常的活锁状态，可以被唤醒
						lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}, "testLockThread");
		
		thread.start();
	}
	
	/**
	 * 线程死锁等待演示
	 *
	 */
	static class SynAddRunnable implements Runnable {
		int a,b;
		
		public SynAddRunnable(int a, int b){
			this.a = a;
			this.b = b;
		}
		
		@Override
		public void run(){
			
			/**
			 * 造成死锁的原因是Integer.valueOf()方法基于减少对象创建次数和节省内存的考虑
			 * [-128, 127]之间的数字会被缓存，当valueOf()方法传入参数在这个范围之内，将直接
			 * 返回缓存中的对象。
			 * 
			 * 示例：代码调用200次Integer.valueOf()方法一共就只返回了两个不同的对象，假如在
			 * 某个线程的两个synchronized块之间发生了一次线程切换，就会出现线程A等着被线程B持有的
			 * Integer.valueOf(1)，线程B又等待着被线程A持有的Integer.valueOf(2)
			 * jsconsole页面可以检测到死锁
			 * 
			 */
			
			synchronized(Integer.valueOf(a)){
				synchronized(Integer.valueOf(b)){
					System.out.println(a + b);
				}
			}
		}
	}
	
	public static void main(String[] args) throws Exception{
		//运行后，执行jconsole命令，切换到线程页签查看main详情
		
		//等待System.in键盘输入，RUNNABLE状态的线程被分配运行时间，
		//但readBytes方法检查到流没有更新时会立刻归还执行令牌，这种等待只消耗很小的CPU资源
//		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//		
//		br.readLine();
//		createBusyThread();
//		
//		br.readLine();
//		Object obj = new Object();
//		createLockThread(obj);
		
		
		
		//死锁测试
		for (int i=0;i<100;i++){
			new Thread(new SynAddRunnable(1,2)).start();
			new Thread(new SynAddRunnable(2,1)).start();
		}
		
	}
}
